package ar.uba.fi.taller2.ftrs.repo;

import java.io.*;

import ar.uba.fi.taller2.ftrs.common.*;
import ar.uba.fi.taller2.ftrs.index.Indexador;
import ar.uba.fi.taller2.ftrs.parser.DocumentParser;

public class RepositoryManager {
	
	// el wd por defecto es un directorio llamado ftrs debajo del 
	// directorio actual de la aplicacion
	public static final String DEFAULT_WD = new String("."+File.separator+"ftrs"+File.separator);
	
	private static String WorkingDirectory;
	
	/// Metodos privados ///
	
	public RepositoryManager() {

		WorkingDirectory = null;
		// obtengo del archivo de configuracion el directorio de trabajo de la aplicacion
		WorkingDirectory = Parameters.getParametros().getMessage("WORKING_DIRECTORY", 1);
		if (WorkingDirectory==null || WorkingDirectory.length()==0) {
			WorkingDirectory = DEFAULT_WD;
		}
		if (!WorkingDirectory.endsWith(File.separator)) {
			WorkingDirectory += File.separator;
		}
	}

	// Agrega al repositorio repName el documento que se halla en docPath
	private void addDocument(String repName, String docPath) throws IOException {

		File fromFile = new File(docPath);
		File toFile = new File(WorkingDirectory+repName+File.separator+"input"+File.separator);

		//validaciones
		if (!fromFile.exists())
			throw new IOException("Error, no existe el archivo: "+ docPath);
		if (!fromFile.isFile())
			throw new IOException("Error, no se puede escribir en el directorio: "+ docPath);
		if (!fromFile.canRead())
			throw new IOException("Error, no se puede leer el archivo: "+ docPath);

		if (toFile.isDirectory())
			toFile = new File(toFile, fromFile.getName());
		else
			throw new IOException("No existe el repositorio "+repName);

		if (toFile.exists()) {
		//	throw new IOException("Error, el archivo "+WorkingDirectory+repName+File.separator+fromFile.getName()+" ya existe.");		      
		} else {
			String parent = toFile.getParent();
			if (parent == null)
				parent = System.getProperty("user.dir");
			File dir = new File(parent);
			if (!dir.exists())
				throw new IOException("Error, No existe el directorio destino: " + parent);
			if (dir.isFile())
				throw new IOException("Error, el destino no es un directorio valido " + parent);
			if (!dir.canWrite())
				throw new IOException("No se puede escribir en el directorio destino " + parent);
		}

		//copio el archivo del origen al destino
		FileInputStream from = null;
		FileOutputStream to = null;
		try {
			from = new FileInputStream(fromFile);
			to = new FileOutputStream(toFile);
			byte[] buffer = new byte[4096];
			int bytesRead;

			while ((bytesRead = from.read(buffer)) != -1)
				to.write(buffer, 0, bytesRead); // write
			
		} finally {
			if (from != null)
				try {
					from.close();
				} catch (IOException e) {
					;
				}
			if (to != null)
				try {
					to.close();
				} catch (IOException e) {
					;
				}
		}    
	}
	
	// metodo recursivo que recorre todos lo archivos de un directorio
	// y los subdirectorios del mismo y para cada archivo invoca a addDocument
	public void visitAllFiles(String repName, File dir) {

		if (dir.isDirectory()) {
			String[] children = dir.list();
			for (int i=0; i<children.length; i++) {
				visitAllFiles(repName, new File(dir, children[i]));
			}
		} else {
			try {
				addDocument(repName, dir.getAbsolutePath());
			} catch (IOException e) {
				System.err.println(e.getMessage());
			}
		}
	}

	/// Metodos publicos ///
	
	// crea un nuevo repositorio con el nombre repName
	public void createRepository(String repName) throws PathAlreadyExistsException, SecurityException {

		File dir = new File(this.WorkingDirectory+repName);
		
		if (!dir.exists()) {

			Boolean success = dir.mkdirs();
			
			// creo los subdirectorios para la administracion del repositorio
			if (success) {
				dir = new File(this.WorkingDirectory+repName+File.separator+"input");
				dir.mkdir();
				dir = new File(this.WorkingDirectory+repName+File.separator+"docs");
				dir.mkdir();
				dir = new File(this.WorkingDirectory+repName+File.separator+"index");
				dir.mkdir();
			}
		}
		//else {
				// The path already exists
			//	throw new PathAlreadyExistsException(this.WorkingDirectory+repName);
		//}
	}
	
	// elimina el repositorio repName
	public void dropRepository(String repName) {
		
		boolean success = (new File(this.WorkingDirectory+repName)).delete();
		if (!success) {
			// Deletion failed
		}
	}
	
	// agrega un documento o directorio completo al repositorio
	// si el path corresponde a un directorio, agrega todos los 
	// documentos del mismo, mas todos los documentos de los 
	// subdirectorios.
	public void addToRepository(String repName, String path) {
		File file = new File(path);
		if ( file.isFile()){
				try {
					this.addDocument(repName, path);
				} catch (IOException e) {
					System.err.println(e.getMessage());
					e.printStackTrace();
				} 
		}
		
		if (file.isDirectory()){
			
			File dir =file;
		    
		    String[] children = dir.list();
		    if (children == null) {
		        // Either dir does not exist or is not a directory
		    } else {
		        for (int i=0; i<children.length; i++) {
		            // Get filename of file or directory
		            String filename = children[i];
		        }
		    }
		    
		    // It is also possible to filter the list of returned files.
		    // This example does not return any files that start with `.'.
		    FilenameFilter filter = new FilenameFilter() {
		        public boolean accept(File dir, String name) {
		        	return !name.startsWith(".");
		        }
		    };
		    children = dir.list(filter);
		    
		    
		    // The list of files can also be retrieved as File objects
		    File[] files = dir.listFiles();
		    
		    // This filter only returns directories
		    FileFilter fileFilter = new FileFilter() {
		        public boolean accept(File file) {
		        	  return file.isFile();

		        }
		    };
		    files = dir.listFiles(fileFilter);
            
		    for (int i=0 ; i<files.length;i++){
		    	try{
		    	this.addDocument(repName, path+File.separator+files[i].getName());
				} catch (IOException e) {
				System.err.println(e.getMessage());
				e.printStackTrace();
				} 
		    }

		
		}
		
		
	}
	
	// genera el indice para el repositorio en cuestion. Si el
	// parametro full es true, se reindexa desde cero (si es que
	// ya se habia indexado el repositorio), si es false se actualiza
	// el indice actual si es que existe.
	public void indexRepository(String repName, Boolean full){
		File file = new File(this.WorkingDirectory+repName+File.separator+"input");
		if (file.isDirectory()){
			
			File dir =file;
		    
		    String[] children = dir.list();
		    if (children == null) {
		        // Either dir does not exist or is not a directory
		    } else {
		        for (int i=0; i<children.length; i++) {
		            // Get filename of file or directory
		            String filename = children[i];
		        }
		    }
		    
		    // It is also possible to filter the list of returned files.
		    // This example does not return any files that start with `.'.
		    FilenameFilter filter = new FilenameFilter() {
		        public boolean accept(File dir, String name) {
		        	return !name.startsWith(".");
		        }
		    };
		    children = dir.list(filter);
		    
		    
		    // The list of files can also be retrieved as File objects
		    File[] files = dir.listFiles();
		    
		    // This filter only returns directories
		    FileFilter fileFilter = new FileFilter() {
		        public boolean accept(File file) {
		        	  return file.isFile();

		        }
		    };
		    files = dir.listFiles(fileFilter);
            
		    for (int i=0 ; i<files.length;i++){
		    	try{
		    		DocumentParser.parseDocument(files[i].getPath().toString());
				} catch (IOException e) {
				System.err.println(e.getMessage());
				e.printStackTrace();
				} 
				catch(Exception e) {	
					 System.out.println(e);
				}
		    }
		    
		
		}
		Indexador indexador = Indexador.getIndexador();
		 indexador.generarIndice();
		
	}
	
	// establece el directorio donde se van a almacenar los archivos
	// administrativos y los archivos ya indexados.
	public void setWorkingDirectory(String path) {}
	
	public String[] listRepositories() {
		File dir = new File(WorkingDirectory+File.separator);
		String[] children=null;
		if (dir.isDirectory()) 
			children = dir.list();
		return children;		
	}
}
